package com.le.tester.webpage.lock;

import java.util.concurrent.locks.StampedLock;

/**
 * 描述：使用jdk1.8的新的StampedLock,写入的时候是一样的，
 * 在读取的时候，提供了验证的方法，和乐观的一个读取锁，但是在有写入数据的时候。就应该使用悲观锁住，保证读取的原子性
 * StampedLock把读锁细分为乐观读和悲观读，能进一步提升并发效率。但这也是有代价的：一是代码更加复杂，二是StampedLock是不可重入锁，不能在一个线程中反复获取同一个锁
 */
public class Point {
    private final StampedLock stampedLock = new StampedLock();

    private double x;

    private double y;

    public void move(double deltaX, double deltaY) {
        //获取到写的锁
        long writeLock = stampedLock.writeLock();
        //没有这种lock.lock()了;
        try {
            deltaX += x;
            deltaY += y;
        } finally {
            stampedLock.unlock(writeLock);
        }

    }

    public double distanceFromOrigin() {
        //获取一个读取数据的乐观锁
        long optimisticRead = stampedLock.tryOptimisticRead();
        //乐观锁，注意线程的原子性（这边读写的重排序和可见性，会导致数据的不准确）
        double currentX = x;
        double currentY = y;

        System.out.println("================================");
        //这里提供了一个是不是线程有写入操作的验证
        if (!stampedLock.validate(optimisticRead)) {
            //如果有的话，就应该保证写入的原子性了,不能用这个乐观锁了呀
            long readLock = stampedLock.readLock();
            try {
                currentX = x;
                currentY = y;
            } finally {
                stampedLock.unlock(readLock);
            }
        }
        return Math.sqrt(currentX * currentX + currentY * currentY);
    }

}
